/*!
 * @author : ZhaoYanbo
 * @email  : zyb920@hotmail.com
 * @created: 2020-10-31
 * @version: 1.0.0.0
 *
 */

#include "OpenALEngine.h"
#include <QtDebug>

OpenALEngine::OpenALEngine()
{
    init();
}

OpenALEngine::~OpenALEngine()
{
    clean();
}

void OpenALEngine::play()
{
    int state;
    alGetSourcei(m_outSourceId, AL_SOURCE_STATE, &state);

    if (state == AL_STOPPED || state == AL_INITIAL)
        alSourcePlay(m_outSourceId);
}

void OpenALEngine::stop()
{
    alSourceStop(m_outSourceId);
    alSourcei(m_outSourceId, AL_BUFFER, 0);
    //
    //alDeleteBuffers(4, bufferID);
    alDeleteSources(1, &m_outSourceId);
}

void OpenALEngine::togglePlay()
{
    int state;
    alGetSourcei(m_outSourceId, AL_SOURCE_STATE, &state);
    if (state == AL_PAUSED)
        alSourcePlay(m_outSourceId);//pause->play
    else if(state == AL_PLAYING)
        alSourcePause(m_outSourceId);
}

void OpenALEngine::setVolume(float v)
{
    m_volume = v;
    alSourcef(m_outSourceId, AL_GAIN, v);
}

float OpenALEngine::getVolume() const
{
    return m_volume;
}
//
int OpenALEngine::openAudioFromQueue(char *data, int dataSize, int aSampleRate, int aBit, int aChannel)
{
    //样本数openal的表示方法
    ALenum format = 0;
    //buffer id 负责缓存,要用局部变量每次数据都是新的地址
    ALuint bufferID = 0;
    if (m_datasize == 0 && m_samplerate == 0 && m_bit == 0 && m_channel == 0)
    {
        if (dataSize != 0 && aSampleRate != 0 && aBit != 0 && aChannel != 0)
        {
            m_datasize = dataSize;
            m_samplerate = aSampleRate;
            m_bit = aBit;
            m_channel = aChannel;
            //计算一帧数据持续时间
            m_oneframeduration = (m_datasize * 1.0 /(m_bit/8) /m_channel /m_samplerate) * 1000 ;
            qDebug() << m_datasize << (m_bit/8) << m_channel << m_samplerate << m_oneframeduration;
        }
    }
    //创建一个buffer
    alGenBuffers(1, &bufferID);
    if (aBit == 8)
    {
        if (aChannel == 1)
        {
            format = AL_FORMAT_MONO8;
        }
        else if(aChannel == 2)
        {
            format = AL_FORMAT_STEREO8;
        }
        else if( alIsExtensionPresent( "AL_EXT_MCFORMATS" ) )
        {
            if( aChannel == 4 )
            {
                format = alGetEnumValue( "AL_FORMAT_QUAD8" );
            }
            if( aChannel == 6 )
            {
                format = alGetEnumValue( "AL_FORMAT_51CHN8" );
            }
        }
    }
    else if( aBit == 16 )
    {
        if( aChannel == 1 )
        {
            format = AL_FORMAT_MONO16;
        }
        else if( aChannel == 2 )
        {
            format = AL_FORMAT_STEREO16;
        }
        else if( alIsExtensionPresent( "AL_EXT_MCFORMATS" ) )
        {
            if( aChannel == 4 )
            {
                format = alGetEnumValue( "AL_FORMAT_QUAD16" );
            }
            if( aChannel == 6 )
            {
                format = alGetEnumValue( "AL_FORMAT_51CHN16" );
            }
        }
    }
    //指定要将数据复制到缓冲区中的数据
    alBufferData(bufferID, format, data, dataSize,aSampleRate);
    //附加一个或一组buffer到一个source上
    alSourceQueueBuffers(m_outSourceId, 1, &bufferID);
    //更新队列数据
    updateQueue();
    //删除一个缓冲 这里不应该删除缓冲，在source里面播放完毕删除
    alDeleteBuffers(1, &bufferID);
    bufferID = 0;
    return 0;
}

bool OpenALEngine::updateQueue()
{
    //播放状态字段
    ALint stateVaue = 0;
    //获取处理队列，得出已经播放过的缓冲器的数量
    alGetSourcei(m_outSourceId, AL_BUFFERS_PROCESSED, &m_numprocessed);
    //获取缓存队列，缓存的队列数量
    alGetSourcei(m_outSourceId, AL_BUFFERS_QUEUED, &m_numqueued);
    //获取播放状态，是不是正在播放
    alGetSourcei(m_outSourceId, AL_SOURCE_STATE, &stateVaue);
    if (stateVaue == AL_STOPPED || stateVaue == AL_PAUSED || stateVaue == AL_INITIAL)
    {
        //如果没有数据,或数据播放完了
        if (m_numqueued < m_numprocessed || m_numqueued == 0 ||(m_numqueued == 1 && m_numprocessed ==1))
        {
            qDebug("finish1");
            //stop();
            //clean();
            return false;
        }
        if (stateVaue != AL_PLAYING)
        {
            play();
        }
    }
    //qDebug() << m_numprocessed << m_numqueued << m_IsplayBufferSize << ((m_IsplayBufferSize * m_oneframeduration) + 0.5);
    //将已经播放过的的数据删除掉
    while(m_numprocessed --)
    {
        ALuint buff;
        //更新缓存buffer中的数据到source中
        alSourceUnqueueBuffers(m_outSourceId, 1, &buff);
        //删除缓存buff中的数据
        alDeleteBuffers(1, &buff);
        //得到已经播放的音频队列多少块
        m_IsplayBufferSize ++;
    }
    //long long time = (long long )((m_IsplayBufferSize * m_oneframeduration) + 0.5);
    return true;
}

bool OpenALEngine::isEnd() const
{
    return m_numqueued == 0;
}

int OpenALEngine::init()
{
    m_Devicde = alcOpenDevice("PCH");
    qDebug() << "1:" << m_Devicde;
    if(m_Devicde)
    {
        m_Context = alcCreateContext(m_Devicde, nullptr);
        qDebug() << "2:" << m_Context;
        alcMakeContextCurrent(m_Context);
    }
    ALfloat SourcePos[] = { 0.0, 0.0, 0.0 };
    ALfloat SourceVel[] = { 0.0, 0.0, 0.0 };
    //创建一个source并设置一些属性
    alGenSources(1, &m_outSourceId);
    alSpeedOfSound(1.0);
    alDopplerVelocity(1.0);
    alDopplerFactor(1.0);
    alSourcef(m_outSourceId, AL_PITCH, 1.0f);//播放速率
    alSourcef(m_outSourceId, AL_GAIN, 1.0f);
    alSourcei(m_outSourceId, AL_LOOPING, AL_FALSE);
    alSourcef(m_outSourceId, AL_SOURCE_TYPE, AL_STREAMING);
    alSourcefv(m_outSourceId, AL_POSITION, SourcePos);
    alSourcefv(m_outSourceId, AL_VELOCITY, SourceVel);
    alSourcef(m_outSourceId, AL_REFERENCE_DISTANCE, 50.0f);
    alDistanceModel(AL_LINEAR_DISTANCE_CLAMPED);
    alListener3f(AL_POSITION, 0, 0, 0);
    return 0;

}

void OpenALEngine::clean()
{
    alDeleteSources(1, &m_outSourceId);
    alcMakeContextCurrent(nullptr);
    alcDestroyContext(m_Context);
    m_Context = nullptr;
    alcCloseDevice(m_Devicde);
}
